package com.power.sifa.ocr.service.impl;

import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.io.FileUtil;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.plf.common.file.service.IFileService;
import com.plf.core.base.model.Ha_attachment;
import com.plf.core.base.service.Ha_attachmentService;
import com.power.sifa.approve.dao.Apl_matter_attachDao;
import com.power.sifa.approve.service.Apl_matter_attachService;
import com.power.sifa.ocr.service.OcrBaiduService;
import com.power.sifa.util.Base64Util;
import com.power.sifa.util.FileUtils;
import com.power.sifa.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
@ConditionalOnProperty(prefix = "ocr.baidu", name = "enable", havingValue = "true")
public class OcrBaiduServiceImpl implements OcrBaiduService {

    @Resource
    private IFileService fileService;

    @Resource
    private Ha_attachmentService ha_attachmentService;

    @Resource
    private Apl_matter_attachDao aplMatterAttachDao;

    @Resource
    private Apl_matter_attachService aplMatterAttachService;

    private String access_token = "24.8ab77e2113db05a8175f40af36df5623.2592000.1697853603.282335-39714330";
    private long token_time = 1695261602604L;


    @Value("${ocr.baidu.apikey:''}")
    private String API_KEY;

    @Value("${ocr.baidu.secretkey:''}")
    private String SECRET_KEY;

    private final String URL_TOKEN = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=%s&client_secret=%s";
    private static final String URL_IDCARD = "https://aip.baidubce.com/rest/2.0/ocr/v1/idcard?access_token=%s";
    private static final String URL_READIMG = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic";

    @Override
    public JSONObject checkIdCard(String filepath, Boolean front) {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("无法获取access_token");
            return null;
        }

        Map<String, Object> param = new HashMap<String, Object>();
        if (front) {
            param.put("id_card_side", "front");
        } else {
            param.put("id_card_side", "back");
        }

        if (filepath.startsWith("http")) {
            // 网络地址
            param.put("url", filepath);
        } else {
            // 本地路径
            byte[] file = FileUtil.readBytes(filepath);
            String imgParam = Base64Encoder.encode(file);
            param.put("image", imgParam);
        }


        JSONObject result = null;
        String response = HttpRequest.post(String.format(URL_IDCARD, token))
                .form(param).execute().body();
        log.info(response);
        result = JSON.parseObject(response);

        return result;
    }

    @Override
    public String readImage(String url) {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("无法获取access_token");
            return null;
        }
        try {
            // 本地文件路径
            String filePath = url;
            byte[] imgData = FileUtils.readFileByBytes(filePath);
            String imgStr = Base64Util.encode(imgData);
            String imgParam = URLEncoder.encode(imgStr, "UTF-8");
            String param = "image=" + imgParam;

            String jsonBody = HttpUtil.post(URL_READIMG, token, param);
            String result = concatenateWords(jsonBody);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String readUrl(String url) {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("无法获取access_token");
            return null;
        }
        try {
            // 网络文件路径
            String param = "url=" + url;
            String jsonBody = HttpUtil.post(URL_READIMG, token, param);
            String result = concatenateWords(jsonBody);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String readPDF(String url) {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("无法获取access_token");
            return null;
        }
        try {
            String fileBase64 = getFileContentAsBase64(url, true);
            String param = "pdf_file=" + fileBase64;
            String jsonBody = HttpUtil.post(URL_READIMG, token, param);
            String result = concatenateWords(jsonBody);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String readBase64(String fileBase64, String fileType) {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("无法获取access_token");
            return null;
        }
        try {
            String param = fileType + fileBase64;
            String jsonBody = HttpUtil.post(URL_READIMG, token, param);
            String result = concatenateWords(jsonBody);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public String readFile(MultipartFile file) throws Exception {
        String token = getAccessToken();
        if (token == null || token.equals("")) {
            log.error("获取access_token失败！");
            throw new RuntimeException("获取access_token失败！");
        }

        String fileType = file.getContentType();
        byte[] bytes = file.getBytes();
        String base64 = Base64Util.encode(bytes);
        String param = URLEncoder.encode(base64, "UTF-8");

        if (fileType.equals("application/pdf")) {
            param = "pdf_file=" + param;
        } else if (fileType.startsWith("image/")) {
            param = "image=" + param;
        } else {
            throw new RuntimeException("文件格式有误，请上传图片或者PDF！");
        }
        String jsonBody = HttpUtil.post(URL_READIMG, token, param);
        String result = concatenateWords(jsonBody);
        return result;

    }

    @Override
    public String readByAttachmentid(String attachmentid) throws Exception {
        Ha_attachment hi_attachment = ha_attachmentService.getById(attachmentid);
        String fileUrl = fileService.getFileUrl(hi_attachment.getBucket(), hi_attachment.getPath());
        log.info("文件地址: {}", fileUrl);

        String fileType = this.getFileTypeFromUrl(fileUrl);
        log.info("文件类型: {}", fileType);
        String result = "";
        if (fileType.startsWith("image/")) {
            result = this.readUrl(fileUrl);
        } else if (fileType.equals("application/pdf")) {
            byte[] fileBytes = this.cloudFileToBase64(fileUrl);
            String base64 = Base64Util.encode(fileBytes);
            String param = "pdf_file=" + URLEncoder.encode(base64, "UTF-8");
            String jsonBody = HttpUtil.post(URL_READIMG, getAccessToken(), param);
            result = concatenateWords(jsonBody);
        } else {
            throw new RuntimeException("文件格式有误，请上传图片或者PDF！");
        }
        log.info("解析结果: {}", result);
        return result;
    }

    /**
     * 获取token
     *
     * @return
     */
    public String getAccessToken() {
        long now = System.currentTimeMillis();

        if (!access_token.equals("") && (token_time + 30 * 24 * 3600000L) > now) {
            return access_token;
        } else {
            String response = HttpRequest.get(String.format(URL_TOKEN, API_KEY, SECRET_KEY)).timeout(5000).execute().body();
            JSONObject result = JSON.parseObject(response);
            access_token = result.getString("access_token");
            token_time = now;
            log.info("access_token: {}", access_token);
            log.info("token_time: {}", token_time);
            return access_token;
        }
    }

    /**
     * 获取文件base64编码
     *
     * @param path      文件路径
     * @param urlEncode 如果Content-Type是application/x-www-form-urlencoded时,传true
     * @return base64编码信息，不带文件头
     * @throws IOException IO异常
     */
    @Override
    public String getFileContentAsBase64(String path, boolean urlEncode) throws IOException {
        byte[] b = Files.readAllBytes(Paths.get(path));
        String base64 = Base64.getEncoder().encodeToString(b);
        if (urlEncode) {
            base64 = URLEncoder.encode(base64, "utf-8");
        }
        return base64;
    }

    /**
     * 判断路径上文件的类型
     *
     * @param filePath
     * @return
     */
    @Override
    public String detectFileType(String filePath) {
        Tika tika = new Tika();
        try {
            File file = new File(filePath);
            return tika.detect(file);
        } catch (IOException e) {
            e.printStackTrace();
            return "Error";
        }
    }

    /**
     * 判断网络路径上的文件类型
     *
     * @param fileUrl
     * @return
     */
    public static String getFileTypeFromUrl(String fileUrl) {
        try {
            URL url = new URL(fileUrl);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");  // 发送HEAD请求获取响应头信息
            connection.connect();

            String contentType = connection.getContentType();

            connection.disconnect();

            return contentType;
        } catch (IOException e) {
            System.out.println("发生异常：" + e.getMessage());
            return null;
        }
    }

    /**
     * 获取网络文件的字节码
     *
     * @param fileUrl
     * @return
     * @throws IOException
     */
    public static byte[] cloudFileToBase64(String fileUrl) throws IOException {
        // 打开URL连接
        URL url = new URL(fileUrl);
        URLConnection urlConnection = url.openConnection();
        InputStream inputStream = urlConnection.getInputStream();

        try (BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
             ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {

            // 读取文件内容到 ByteArrayOutputStream
            byte[] buffer = new byte[4096]; // 缓冲区大小可以根据需要调整
            int bytesRead;
            while ((bytesRead = bufferedInputStream.read(buffer)) != -1) {
                byteArrayOutputStream.write(buffer, 0, bytesRead);
            }

            // 获取字节数组
            byte[] fileBytes = byteArrayOutputStream.toByteArray();
            return fileBytes;
        } finally {
            // 关闭输入流
            inputStream.close();
        }
    }

    /**
     * 获取到的json记结果处理
     *
     * @param json
     * @return
     */
    public String concatenateWords(String json) {
        Gson gson = new Gson();
        JsonObject jsonObject = gson.fromJson(json, JsonObject.class);
        JsonArray wordsArray = jsonObject.getAsJsonArray("words_result");

        StringBuilder result = new StringBuilder();
        for (JsonElement element : wordsArray) {
            JsonObject wordObject = element.getAsJsonObject();
            if (wordObject.has("words")) {
                result.append(wordObject.get("words").getAsString()).append("\n");
            }
        }
        return result.toString();
    }
}
